#include "stdafx.h"
#include "Matrice.h"

Matrice::Matrice()
{
	for (int i = 0; i < 4; i++)
		for (int j = 0; j < 4; j++)
			data[i][j] = 0;
}
Matrice::Matrice(float *c)
{
	for (int i = 0; i < 4; i++)
		for (int j = 0; j < 4; j++)
			data[i][j] = *(c+i*4+j);
}

void Matrice::createGlobObs(Vecteur u, Vecteur vup,Vecteur v, Point origine){

	data[0][0] = u.getX();		data[0][1] = u.getY();		data[0][2] = u.getZ();		data[0][3] = 0; 
	data[1][0] = vup.getX();	data[1][1] = vup.getY();	data[1][2] = vup.getZ();	data[1][3] = 0; 
	data[2][0] = v.getX();		data[2][1] = v.getY();		data[2][2] = v.getZ();		data[2][3] = 0; 
	data[3][0] = origine.getX();data[3][1] = origine.getY();data[3][2] = origine.getZ();data[3][3] = 1; 
} 

void Matrice::createObsGlob(Vecteur u, Vecteur vup,Vecteur v, Point origine){

	data[0][0] = u.getX();	 data[0][1] = vup.getX();	data[0][2] = v.getX();	  data[0][3] = origine.getX(); 
	data[1][0] = u.getY();   data[1][1] = vup.getY();	data[1][2] = v.getY();    data[1][3] = origine.getY(); 
	data[2][0] = u.getZ();   data[2][1] = vup.getZ();   data[2][2] = v.getZ();   data[2][3] = origine.getZ(); 
	data[3][0] = 0;          data[3][1] = 0;			data[3][2] = 0;		      data[3][3] = 1; 
} 

Matrice::Matrice(Matrice const& m)
{
	for (int i = 0; i < 4; i++)
		for (int j = 0; j < 4; j++)
			data[i][j] = m.data[i][j];
}

Matrice::~Matrice(){}

Matrice& Matrice::operator=(Matrice const& m)
{
	for (int i = 0; i < 4; i++)
		for (int j = 0; j < 4; j++)
			data[i][j] = m.data[i][j];

	return *this;
}

float Matrice::getData(int i, int j)
{
	return data[i][j];
}

void Matrice::setData(int i, int j, float value)
{
	data[i][j] = value;
}

Matrice Matrice::loadMatriceNulle()
{
	Matrice m;
	
	for (int i = 0; i < 4; i++)
		for (int j = 0; j < 4; j++)
			m.data[i][j] = 0;

	return m;
}

Matrice Matrice::loadIdentite()
{
	Matrice m = loadMatriceNulle();

	for (int i = 0; i < 4; i++)
		m.data[i][i] = 1;

	return m;
}

Matrice Matrice::multiplication(Matrice const& m)
{
	Matrice m1 = loadMatriceNulle();
	
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			for (int k = 0; k < 4; k++)
				m1.data[i][j] += data[i][k] * m.data[k][j];
		}
	}

	return m1;
}

Matrice Matrice::operator*(Matrice const& m)
{
	return multiplication(m);
}

Vecteur Matrice::operator*(Vecteur v)
{
	Vecteur v1;

	v1.setX(data[0][0]*v.getX() + data[0][1]*v.getY() + data[0][2]*v.getZ() + data[0][3]*0);
	v1.setY(data[1][0]*v.getX() + data[1][1]*v.getY() + data[1][2]*v.getZ() + data[1][3]*0);
	v1.setZ(data[2][0]*v.getX() + data[2][1]*v.getY() + data[2][2]*v.getZ() + data[2][3]*0);

	return v1;
}

Point Matrice::operator*(Point p)
{
	Point p1;

	p1.setX(data[0][0]*p.getX() + data[0][1]*p.getY() + data[0][2]*p.getZ() + data[0][3]*p.getW());
	p1.setY(data[1][0]*p.getX() + data[1][1]*p.getY() + data[1][2]*p.getZ() + data[1][3]*p.getW());
	p1.setZ(data[2][0]*p.getX() + data[2][1]*p.getY() + data[2][2]*p.getZ() + data[2][3]*p.getW());
	p1.setW(data[3][0]*p.getX() + data[3][1]*p.getY() + data[3][2]*p.getZ() + data[3][3]*p.getW());

	p1.normalize();

	return p1;
}

void Matrice::translation(float x, float y, float z)
{
	Matrice m1 = loadIdentite();
	Matrice m_temp;

	m1.data[0][3] = x;
	m1.data[1][3] = y;
	m1.data[2][3] = z;

	m_temp = multiplication(m1);

	for (int i = 0; i < 4; i++)
		for (int j = 0; j < 4; j++)
			data[i][j] = m_temp.data[i][j];
}

void Matrice::translation(float *translation_factor)
{
	translation(translation_factor[0], translation_factor[1], translation_factor[2]);
}

void Matrice::invTranslation(float x, float y, float z)
{
	Matrice m1 = loadIdentite();
	Matrice m_temp;

	m1.data[0][3] = -x;
	m1.data[1][3] = -y;
	m1.data[2][3] = -z;

	m_temp = m1.multiplication(*this);

	for (int i = 0; i < 4; i++)
		for (int j = 0; j < 4; j++)
			data[i][j] = m_temp.data[i][j];
}

void Matrice::invTranslation(float *translation_factor)
{
	invTranslation(translation_factor[0], translation_factor[1], translation_factor[2]);
}

Matrice Matrice::rotationX(float angle)
{
	Matrice m = loadIdentite();
	
	m.data[1][1] = cos(angle*PI/180);
	m.data[1][2] = -sin(angle*PI/180);
	m.data[2][1] = sin(angle*PI/180);
	m.data[2][2] = cos(angle*PI/180);

	return m;
}

Matrice Matrice::rotationY(float angle)
{
	Matrice m = loadIdentite();

	m.data[0][0] = cos(angle*PI/180);
	m.data[0][2] = sin(angle*PI/180);
	m.data[2][0] = -sin(angle*PI/180);
	m.data[2][2] = cos(angle*PI/180);

	return m;
}

Matrice Matrice::rotationZ(float angle)
{
	Matrice m = loadIdentite();

	m.data[0][0] = cos(angle*PI/180);
	m.data[0][1] = -sin(angle*PI/180);
	m.data[1][0] = sin(angle*PI/180);
	m.data[1][1] = cos(angle*PI/180);
	
	return m;
}

void Matrice::rotation(float angleX, float angleY, float angleZ)
{
	Matrice m_temp = loadIdentite();

	m_temp = m_temp.multiplication(rotationZ(angleZ));
	m_temp = m_temp.multiplication(rotationY(angleY));
	m_temp = m_temp.multiplication(rotationX(angleX));
	m_temp = multiplication(m_temp);

	for (int i = 0; i < 4; i++)
		for (int j = 0; j < 4; j++)
			data[i][j] = m_temp.data[i][j];
}

void Matrice::rotation(float *rotation_factor)
{
	rotation(rotation_factor[0], rotation_factor[1], rotation_factor[2]);
}

void Matrice::invRotation(float angleX, float angleY, float angleZ)
{
	Matrice m_temp = loadIdentite();

	m_temp = m_temp.multiplication(rotationX(-angleX));
	m_temp = m_temp.multiplication(rotationY(-angleY));
	m_temp = m_temp.multiplication(rotationZ(-angleZ));
	m_temp = m_temp.multiplication(*this);

	for (int i = 0; i < 4; i++)
		for (int j = 0; j < 4; j++)
			data[i][j] = m_temp.data[i][j];
}

void Matrice::invRotation(float *rotation_factor)
{
	invRotation(rotation_factor[0], rotation_factor[1], rotation_factor[2]);
}

Matrice Matrice::transposee()
{
	Matrice m = loadMatriceNulle();
	for(int i = 0 ; i < 4 ; i ++)
		for(int j = 0 ; j < 4 ; j ++)
			m.data[j][i] = data[i][j];

	return m;
}
